package com.huawei.mptcp.upload;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.net.*;
import java.net.DatagramSocket;
 
import com.huawei.mptcp.testapp.MptcpMainActivity;
import com.huawei.mptcp.utils.ExportDataCsvUtil;
import com.huawei.mptcp.utils.GlobalConfig;
import com.huawei.mptcp.utils.ILogUtil;
import com.huawei.wireless.ConnectionChangeReceiver;



/**
 * upload file or download file from server socket
 * 
 * @author hujiangshui
 *
 */
public class UploadDownLoadMachine extends Thread implements Runnable {
	private static final String TAG = "MptcpTestUploadDownload";
	
	// 0: upload client--->server , 1: download server---->client
	// 2: meas client send data to server side, wait server response
	private static int testMode = -1;
	
	//if network changed ,then recreate socket and retransmit data
	private Socket tcpsocket = null;
	private DatagramSocket udpsocket = null;
	private DatagramPacket sendPacket = null;
	private DatagramPacket recvPacket = null;
	
	
	//export test data to csv file
	public static ArrayList<Double> collectedData = new ArrayList<Double>();
	
	private static final int allTestTimes = 1000;
	private static final int waitTimeMills = 400; //
	private static long firstStartTime = 0L;
	
	/**
	 * testMode 0:upload , 1:download
	 * author: hujiangshui
	 */
	@Override
	public void run() {
		try {
			
			MptcpMainActivity.updateAlarmInfor("success:begin mptcp test...");
			
			tcpsocket = new Socket(GlobalConfig.tcpSocketIP, GlobalConfig.tcpSocketPort);
			MptcpMainActivity.updateAlarmInfor("success:socket connect success:"+GlobalConfig.tcpSocketIP+":"+GlobalConfig.tcpSocketPort);
				
			switch (testMode) {
				case 0:
							
					ILogUtil.d(TAG, "thread begain upload");
						
					MptcpMainActivity.updateAlarmInfor("success:thread begain upload");
					
					uploadFile();
					
					MptcpMainActivity.updateAlarmInfor("success:upload test finished");
					
					break;
				case 1:
								
					ILogUtil.d(TAG, "thread begain download");
					MptcpMainActivity.updateAlarmInfor("success:start to received bytes from server...");
					downloadFile();
					break;
		
				case 2:
					ILogUtil.d(TAG, "thread begain test rtt");
					MptcpMainActivity.updateAlarmInfor("success:begin rtt test...");
					tcpsendDataToServerAndReadDataFromServer();
					MptcpMainActivity.updateAlarmInfor("success:end test rtt");
					break;
				default:
					MptcpMainActivity.updateAlarmInfor("failed:please chose test mode, include uplink throughput, downlink throughput ,rtt test");
					break;
			}
			
		} catch (Exception e) {
			MptcpMainActivity.updateAlarmInfor("failed:occure some exception");
			ILogUtil.exception(TAG, e);
			if (tcpsocket != null)
				try {
					tcpsocket.close();
				} catch (IOException e1) {
					ILogUtil.exception(TAG, e1);
				}
		}
		
		
	}

	/**
	 * set test machine test mode and begain test
	 * @param testModeType
	 */
	public static void setTestMode(int testModeType){
		UploadDownLoadMachine.testMode = testModeType;
	}


   /**
    out.writeUTF(filePath);
    out.writeUTF(file.getName());
    out.flush();
    out.writeLong((long) file.length());
    out.flush();
     * upload
     * @param filePath
     * @throws Exception
     */
    public void uploadFile() {
    	DataInputStream inputStream = null;
    	DataOutputStream outStream = null;
        try {
            outStream = new DataOutputStream(tcpsocket.getOutputStream());

            byte[] tempByte = new byte[1024 * 8];
    		for(int i=0;i<tempByte.length;i++){
    			tempByte[i]='a';
    		}
            ILogUtil.d(TAG, "read file and begain use socket uplaod");
     
			MptcpMainActivity.updateAlarmInfor("success:read file and begain use socket uplaod");
			int counterByte = 0;
			long counterStartTime = System.currentTimeMillis();
            while (true) {       
            	outStream.write(tempByte, 0, tempByte.length);
            	outStream.flush();
            	counterByte+=tempByte.length;
            	double currentCostTime = (System.currentTimeMillis()-counterStartTime)/1000.0;// seconds
            	if(currentCostTime>1) {
            		double transferRate = counterByte*8/(currentCostTime*1000000);
            		
            		BigDecimal formatD = new BigDecimal(transferRate);
            		collectedData.add(formatD.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue());
            		counterByte = 0;
            		counterStartTime = System.currentTimeMillis();
//                		ILogUtil.d(TAG, "upload file send bytes "+read);
            		
            		if(collectedData.size()>40){
            			break;
            		}
            	}
                
            }
            ILogUtil.d(TAG, "begain export data to csv");
            ExportDataCsvUtil.exportDataCsvWithAppend(GlobalConfig.storeDir, GlobalConfig.csvTransferRateFileName, collectedData);
            ILogUtil.d(TAG, "upload file finished");
            MptcpMainActivity.updateAlarmInfor("success:finished");
        } catch (Exception e) {
        	ILogUtil.exception(TAG, e);
        } finally {
        	try {
	            if (inputStream != null) {
	            	inputStream.close();
	            }
	            if(outStream != null) {
	            	outStream.close();
	            }
        	} catch (IOException e) {
				ILogUtil.exception(TAG, e);
			}
        }
        
    }


    /*
     * if (storeDownloadFile.exists()) {
					storeDownloadFile.delete();
				}
	   handler.sendMessage(msg);
	
     * author: hujiangshui
     */
    public void downloadFile() {
    	DataInputStream inputStream = null;
    	DataOutputStream fileOut = null;
		try {
			ILogUtil.d(TAG, "receive bytes from server, test down stream!!");
			MptcpMainActivity.updateAlarmInfor("success:receive bytes from server");
			
			inputStream = new DataInputStream(new BufferedInputStream(tcpsocket.getInputStream()));

			byte[] buf = new byte[1024 * 8];
			
			
			//count rate
			int counterByte = 0;
			long counterStartTime = System.currentTimeMillis();
			//export test data to csv file
			ArrayList<Double> collectedData = new ArrayList<Double>();
			
			int readBytes = 0;
			while (true) {
				if ((readBytes = inputStream.read(buf))!= -1) {
					
					counterByte+=readBytes;
                	double currentCostTime = (System.currentTimeMillis()-counterStartTime)/1000.0;// seconds
                	if(currentCostTime>1) {
                		double transferRate = counterByte*8/(currentCostTime*1000000);
                		
                		BigDecimal formatD = new BigDecimal(transferRate);  
                		collectedData.add(formatD.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue());
                		MptcpMainActivity.updateAlarmInfor("success:transferRate "+transferRate+" Mbps");
                		counterByte = 0;
                		counterStartTime = System.currentTimeMillis();
                		if(collectedData.size()>40){
                			break;
                		}
                	}
                	
				}else{
					ILogUtil.d(TAG, "receive from server finished");
					MptcpMainActivity.updateAlarmInfor("success:receive bytes from server finished!");
					break;
				}
				
			}
			
			ILogUtil.d(TAG, "export receive rate data to csv file");
			MptcpMainActivity.updateAlarmInfor("success:export receive rate data to csv file!");
			ExportDataCsvUtil.exportDataCsvWithAppend(GlobalConfig.storeDir, GlobalConfig.csvTransferRateFileName, collectedData);
			
		} catch (Exception e) {
			ILogUtil.exception(TAG, e);
		} finally {
			try {
				if(inputStream != null) {
					inputStream.close();
				}
				if(fileOut != null) {
					fileOut.close();
				}
				if(tcpsocket != null){
					tcpsocket.close();
				}
			}catch(Exception e1) {
				ILogUtil.exception(TAG, e1);
			}	
		}
    }

    /**
     * network switch from wifi to lte
     */
    public void tcpsendDataToServerAndReadDataFromServer(){
    	
    	DataInputStream inputStream = null;
    	DataOutputStream outStream = null;
    	
    	boolean isReconnected = false;
    	long counterStartTime = 0;
    	long lastSendDataTime=0L; //recored last time 
    	int testTimes = 0; 
    	
		byte[] tempByte = new byte[1024];
		for(int i=0;i<tempByte.length;i++){
			tempByte[i]='a';
		}
		
    	try{
    		
    		outStream = new DataOutputStream(tcpsocket.getOutputStream());
    		inputStream = new DataInputStream(tcpsocket.getInputStream());
    		
    		while(testTimes < allTestTimes){
    			try{
    				
					byte[] tempBy = String.valueOf(testTimes).getBytes();
					for(int k=0;k<tempBy.length;k++){
						tempByte[k] = tempBy[k];
					}
					
					counterStartTime = System.currentTimeMillis();
					ILogUtil.d(TAG, "rtt test write");
					
					if(testTimes == 0){
	    	    		firstStartTime = counterStartTime;
	    			}
					
					outStream.write(tempByte);
					outStream.flush();
					ILogUtil.d(TAG, "rtt test flush");
					int readServerBytes = inputStream.read(tempByte);
		    		if( readServerBytes != -1){
		    			long cunterEndTime = System.currentTimeMillis();
		    			if(isReconnected){
		    				double rtt = (cunterEndTime - lastSendDataTime)*1.00;
			    			collectedData.add(rtt);
			    			isReconnected = false;
		    			}else{
		    				double rtt = (cunterEndTime - counterStartTime)*1.00;
			    			collectedData.add(rtt);
		    			}
		    			
		    			
		    		}
		    		ILogUtil.d(TAG, "rtt test write times:"+testTimes);
		    		testTimes++;
    			}catch(Exception e){
    				ILogUtil.exception(TAG, e);
    				
    				try{
    	    			if(inputStream != null)inputStream.close();
    	    			if(outStream != null)outStream.close();
    	    			if(tcpsocket != null) tcpsocket.close();
    	    			ILogUtil.d(TAG, "close all connection");
    	    		}catch(Exception e1){
    	    			ILogUtil.exception(TAG, e1);
    	    		}
    				while(true){
    					try{
	    					tcpsocket = new Socket(GlobalConfig.tcpSocketIP, GlobalConfig.tcpSocketPort);
	    					if(tcpsocket.isConnected()){
	    						break;
	    					}
	    					Thread.currentThread().sleep(10);
    					}catch(Exception e2){e2.printStackTrace();}
    				}
					MptcpMainActivity.updateAlarmInfor("success:socket reconnect success:"+GlobalConfig.tcpSocketIP+":"+GlobalConfig.tcpSocketPort);
					
					outStream = new DataOutputStream(tcpsocket.getOutputStream());
		    		inputStream = new DataInputStream(tcpsocket.getInputStream());
		    		
		    		isReconnected = true;
		    		
		    		lastSendDataTime = counterStartTime;
    			}
			
    			
    			
    			
    			
    		}
    		
    		
    		
			long allCostTime = System.currentTimeMillis() - firstStartTime;
			MptcpMainActivity.updateAlarmInfor("success:all cost time "+allCostTime+" ms");
		
			ILogUtil.d(TAG, "second rtt reconnected test finished");
    		
			MptcpMainActivity.updateAlarmInfor("success:second export rtt datas to csv file!");
			ExportDataCsvUtil.exportDataCsvWithAppend(GlobalConfig.storeDir, GlobalConfig.csvRttFileName, collectedData);
			
    		
    	}catch(Exception e){
    		ILogUtil.exception(TAG, e);
    		MptcpMainActivity.updateAlarmInfor("failed:reconnected errror!");
    	}finally{
    		try{
    			if(inputStream != null)inputStream.close();
    			if(outStream != null)outStream.close();
    			if(tcpsocket != null) tcpsocket.close();
    		}catch(Exception e1){
    			ILogUtil.exception(TAG, e1);
    		}
    	}
    	
    }
   
    
    
}


